﻿using System;
using System.Collections.Generic;
using base31.Services.Hub.Helpers;

namespace base31.Services.Hub.Models
{
    /// <summary>
    /// Represents a publishing event to deliver to subscribers.
    /// This model is meant to be used together with Subscription entities. When a
    /// feed has new published data and needs to be pushed to subscribers, one of
    /// these entities will be inserted. The background worker should iterate
    /// through all Subscription entities for this topic, sending them the event
    /// payload. The Update() method should be used to track the progress of the
    /// background worker as well as any Subscription entities that failed delivery.
    /// The key_name for each of these entities is unique. It is up to the event
    /// injection side of the system to de-dupe events to deliver. For example, when
    /// a publish event comes in, that publish request should be de-duped immediately.
    /// Later, when the feed puller comes through to grab feed diffs, it should insert
    /// a single event to deliver, collapsing any overlapping publish events during
    /// the delay from publish time to feed pulling time.
    /// </summary>
    public class EventToDeliver
    {
        public string Topic { get; set; }
        public string TopicHash { get; set; }
        public string LastCallback { get; set; }
        public List<string> FailedCallbacks { get; set; }
        public string DeliveryMode { get; set; }
        public int RetryAttempts { get; set; }
        public DateTime LastModified { get; set; }
        public bool TotallyFailed { get; set; }
        public string ContentType { get; set; }
        public int MaxFailures { get; set; }

        /// <summary>
        /// Creates an event to deliver for a topic and set of published entries.
        /// </summary>
        /// <param name="topic">The topic that had the event.</param>
        /// <param name="format">Format of the feed, 'atom', 'rss', or 'arbitrary'.</param>
        /// <param name="contentType">The original content type of the feed, fetched from the
        /// server, if any. May be empty.</param>
        /// <param name="headerFooter">The header and footer of the published feed into which
        /// the entry list will be spliced. For arbitrary content this is the
        /// full body of the resource.</param>
        /// <param name="entryPayloads">List of strings containing entry payloads (i.e., all
        /// XML data for each entry, including surrounding tags) in order of newest
        /// to oldest.</param>
        /// <param name="setParent">Set the parent to the FeedRecord for the given topic. This is
        /// necessary for the parse_feed flow's transaction. Default is True. Set
        /// to False if this EventToDeliver will be written outside of the
        /// FeedRecord transaction.</param>
        /// <param name="maxFailures">Maximum number of failures to allow for this event. When
        /// default it will use the MAX_DELIVERY_FAILURES constant.</param>
        /// <returns>A new EventToDeliver instance that has not been stored.</returns>
        public EventToDeliver CreateEventForTopic(string topic,
                                                  string format,
                                                  string contentType,
                                                  string headerFooter,
                                                  string entryPayloads,
                                                  bool setParent = true,
                                                  int maxFailures = Constants.MAX_DELIVERY_FAILURES
            )
        {
            return null;
        }

        /// <summary>
        /// How many subscribers to retrieve at a time while delivering
        /// the event. Defaults to EVENT_SUBSCRIBER_CHUNK_SIZE.
        /// </summary>
        /// <param name="chunkSize"></param>
        /// <returns>Tuple (more_subscribers, subscription_list) where:
        /// more_subscribers: True if there are more subscribers to deliver to
        ///   after the returned 'subscription_list' has been contacted; this value
        ///   should be passed to update() after the delivery is attempted.
        /// subscription_list: List of Subscription entities to attempt to contact
        ///   for this event.</returns>
        public Tuple<bool, List<string>> GetNextSubscribers(int chunkSize = Constants.EVENT_SUBSCRIBER_CHUNK_SIZE)
        {
            return null;
        }

        /// <summary>
        /// Updates an event with work progress or deletes it if it's done.
        /// Reschedules another Task to run to handle this event delivery if needed.
        /// </summary>
        /// <param name="moreCallbacks">True if there are more callbacks to deliver, False if
        /// there are no more subscribers to deliver for this feed.</param>
        /// <param name="moreFailedCallbacks">Iterable of Subscription entities for this event
        /// that failed to deliver.</param>
        /// <param name="maxFailures">Maximum failures to allow before giving up.</param>
        /// <param name="retryPeriod">Initial period for doing exponential (base-2) backoff.</param>
        public void Update(bool moreCallbacks,
                           List<Subscription> moreFailedCallbacks,
                           int maxFailures = Constants.MAX_DELIVERY_FAILURES,
                           int retryPeriod = Constants.DELIVERY_RETRY_PERIOD)
        {
        }

        /// <summary>
        /// Enqueues a Task that will execute this EventToDeliver.
        /// </summary>
        public void Enqueue()
        {
        }
    }
}